﻿using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using SlimDX;

using D3DC = SlimDX.D3DCompiler;
using DX10 = SlimDX.Direct3D10;
using DXGI = SlimDX.DXGI;

namespace TriDVisualizer
{
    public class SimpleBox
    {
        private DX10.Buffer m_vertexBuffer;
        private DX10.Buffer m_indexBuffer;
        private DX10.InputLayout m_vertexLayout;
        private DX10.Effect m_effect;
        private DX10.EffectTechnique m_effectTechnique;
        private DX10.EffectPass m_effectPass;
        private DX10.EffectMatrixVariable m_transformVariable;

        public void LoadResources(DX10.Device device)
        {
            Vertex[] vertices = new Vertex[]
            {
                new Vertex(new Vector3(-1, -1, -1), (uint)Color.Red.ToArgb()),
                new Vertex(new Vector3(1, -1, -1), (uint)Color.LightBlue.ToArgb()),
                new Vertex(new Vector3(1, -1, 1), (uint)Color.LightCyan.ToArgb()),
                new Vertex(new Vector3(-1, -1, 1), (uint)Color.CadetBlue.ToArgb()),
                new Vertex(new Vector3(-1, 1, -1), (uint)Color.Red.ToArgb()),
                new Vertex(new Vector3(1,1,-1), (uint)Color.Orange.ToArgb()),
                new Vertex(new Vector3(1,1,1), (uint)Color.Goldenrod.ToArgb()),
                new Vertex(new Vector3(-1, 1,1), (uint)Color.Yellow.ToArgb())
            };

            short[] indices = new short[]
            {
                4,1,0,4,5,1,
                5,2,1,5,6,2,
                6,3,2,6,7,3,
                7,0,3,7,4,0,
                7,5,4,7,6,5,
                2,3,0,2,0,1
            };

            DataStream outStream = new DataStream(8 * Marshal.SizeOf(typeof(Vertex)), true, true);
            DataStream outStreamIndex = new DataStream(36 * Marshal.SizeOf(typeof(short)), true, true);

            for (int loop = 0; loop < vertices.Length; loop++)
            {
                outStream.Write<Vertex>(vertices[loop]);
            }

            for(int loop=0 ; loop<indices.Length ; loop++)
            {
                outStreamIndex.Write<short>(indices[loop]);
            }

            outStream.Position = 0;
            outStreamIndex.Position = 0;
            
            DX10.BufferDescription bufferDescription = new DX10.BufferDescription();
            bufferDescription.BindFlags = DX10.BindFlags.VertexBuffer;
            bufferDescription.CpuAccessFlags = DX10.CpuAccessFlags.None;
            bufferDescription.OptionFlags = DX10.ResourceOptionFlags.None;
            bufferDescription.SizeInBytes = 8 * Marshal.SizeOf(typeof(Vertex));
            bufferDescription.Usage = DX10.ResourceUsage.Default;

            DX10.BufferDescription bufferDescriptionIndex = new DX10.BufferDescription();
            bufferDescriptionIndex.BindFlags = DX10.BindFlags.IndexBuffer;
            bufferDescriptionIndex.CpuAccessFlags = DX10.CpuAccessFlags.None;
            bufferDescriptionIndex.OptionFlags = DX10.ResourceOptionFlags.None;
            bufferDescriptionIndex.SizeInBytes = 36 * Marshal.SizeOf(typeof(short));
            bufferDescriptionIndex.Usage = DX10.ResourceUsage.Default;

            m_vertexBuffer = new DX10.Buffer(device, outStream, bufferDescription);
            m_indexBuffer = new DX10.Buffer(device, outStreamIndex, bufferDescriptionIndex);
            outStream.Close();
            outStreamIndex.Close();

            m_effect = DX10.Effect.FromFile(device, "Shaders/SimpleRendering.fx", "fx_4_0", D3DC.ShaderFlags.None, D3DC.EffectFlags.None);
            m_effectTechnique = m_effect.GetTechniqueByIndex(0);
            m_effectPass = m_effectTechnique.GetPassByIndex(0);
            m_transformVariable = m_effect.GetVariableByName("WorldViewProj").AsMatrix();

            DX10.InputElement[] inputElements = new DX10.InputElement[]
            {
                new DX10.InputElement("POSITION",0,SlimDX.DXGI.Format.R32G32B32_Float,0,0),
                new DX10.InputElement("COLOR",0,SlimDX.DXGI.Format.R8G8B8A8_UNorm,12,0)
            };
          
            m_vertexLayout = new DX10.InputLayout(device, inputElements, m_effectPass.Description.Signature);
        }

        public void Render(DX10.Device device, Matrix world, Matrix viewProj)
        {
            device.InputAssembler.SetInputLayout(m_vertexLayout);
            device.InputAssembler.SetPrimitiveTopology(DX10.PrimitiveTopology.TriangleList);
            device.InputAssembler.SetIndexBuffer(m_indexBuffer, DXGI.Format.R16_UInt, 0);
            device.InputAssembler.SetVertexBuffers(0, new DX10.VertexBufferBinding(m_vertexBuffer, Marshal.SizeOf(typeof(Vertex)), 0));
           
            m_transformVariable.SetMatrix(world * viewProj);

            m_effectPass.Apply();
            device.DrawIndexed(36, 0, 0);
        }
    }
}
